package com.manli.api.controller.wechat;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.sql.ResultSet;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

import com.manli.api.base.config.JwtAuthTokenTimeConfig;
import com.manli.api.base.exception.MyException;
import com.manli.api.dto.wechat.WeChatUserLocation;
import com.manli.api.enums.ResultEnums;
import com.manli.api.pojo.*;
import com.manli.api.service.wechat.WeChatUserLocationService;
import com.manli.api.util.JwtUtils;
import com.manli.api.util.ResultUtil;
import com.manli.common.utils.WeatherUtil;
import com.manli.common.utils.qiniu.TencentMapUtils;
import com.manli.wechat.pojo.WeChatQrcodePojo;
import com.manli.wechat.pojo.WeChatUserInfo;
import com.manli.wechat.utils.*;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import com.alibaba.fastjson.JSONObject;
import com.manli.api.base.annotation.Permissions;
import com.manli.api.dto.SysWechatConfig;
import com.manli.api.service.WechatService;
import com.manli.api.util.WeChatConfigUtil;
import com.manli.api.util.WeChatOverUtil;
import com.manli.common.utils.RandomUtils;
import com.manli.common.utils.WeChatSignUtils;
import com.manli.qq.weixin.mp.aes.AesException;
import com.manli.qq.weixin.mp.aes.SHA1;
import com.manli.wechat.pojo.WeChatJsSdkAuthPojo;
import com.manli.wechat.utils.wechattemplate.WeChatTemplateUtil;
import com.manli.wechat.utils.wechattemplate.WeixinTemplateList;
import com.manli.wechat.utils.wechattemplate.WeixinTemplateSender;
import com.manli.wechat.utils.wxpay.config.MyWxPayConfig;
import com.manli.wechat.utils.wxpay.sdk.WXPay;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
@Api(tags = "微信公众号模块")
public class WechatController {
	
	Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 *漫狸科技(温州)
	 */
	private String appId = "wx6f56d14c68184b2f";

	@Autowired
	WechatService wechatService;
	
	@Autowired
	WeChatConfigUtil weChatConfigUtil;
	
	@Autowired
	WeChatOverUtil weChatOverUtil;

	@Autowired
	RedisTemplate redisTemplate;

	@Autowired
	WeChatUserLocationService weChatUserLocationService;
	
	/**
	 * 开发者通过检验signature对请求进行校验（下面有校验方式）。
	 * 若确认此次GET请求来自微信服务器，请原样返回echostr参数内容，则接入生效，成为开发者成功，否则接入失败
	 * @param signature 微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
	 * @param timestamp 时间戳
	 * @param nonce 随机数
	 * @param echostr 随机字符串
	 * @return
	 * @throws AesException 
	 */
	@ApiOperation(value="微信配置服务器地址验证", notes="验证请求是否正常")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping(value="/wechat/receiveMsg", method=RequestMethod.GET)
	public @ResponseBody String receiveMsg( String signature,String timestamp,String nonce,String echostr) throws AesException {
		SysWechatConfig sysWechatConfig = weChatConfigUtil.getWeChatByAppid(appId);
		String token = sysWechatConfig.getServerToken();
		if(SHA1.getSHA1(token, timestamp, nonce, "").equals(signature)) {
			return echostr;
		};
		return null;
	}
	/**
	 * @param msg
	 * @param msg_signature
	 * @param timestamp
	 * @param nonce
	 * @param echostr
	 * @return
	 * @throws Exception
	 */
	@ApiOperation(value="微信消息管理", notes="微信发送消息到服务器")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping(value="/wechat/receiveMsg", method=RequestMethod.POST)
	public @ResponseBody String receiveMsg(@RequestBody String msg,String msg_signature,String timestamp,String nonce,String echostr) throws Exception {

		return wechatService.receiveMsg(appId,msg,msg_signature,timestamp,nonce,echostr);
	}
	
	@ApiOperation(value="微信消息管理", notes="微信发送模板")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping(value="/wechat/sendMsgToUser", method=RequestMethod.GET)
	public void sendMsgToUser() throws Exception {

		SysWechatConfig config = weChatConfigUtil.getWeChatByAppid(appId);
		WeChat weChat = new WeChat(config.getAppId(), config.getAppSecret());
		String accessToken = weChatOverUtil.getAccessToken(weChat);
		WeixinTemplateSender.sendWechatmsgToUser("oXzMAwMhnYDAcX_m9ZDAxSCjsS4c", WeixinTemplateList.TX_RESULT_TOPIC, "https://www.baidu.com", WeChatTemplateUtil.packageMessage(
				"manli1",null,
				"manli2",null,
				"manli3",null,
				"manli4",null,
				"manli5",null,
				"manli6",null,
				"manli7",null), accessToken);
	
	}
	
	@ApiOperation(value="微信网页开发", notes="获取网页授权")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@GetMapping(value="/wechat/getWechatAuth")
	public String getWechatAuth(String redirectUrl , String state) throws Exception {
		//1 redirectUrl 页面希望跳转的地址 redirectUrl必须被编码过
		//例如 http://**.com?redirect_url=decodeURI("http://**.com?a=1&b=1")
		//2 进入方法钱呗解码了所以需要 继续编码
		//redirectUrl = URLEncoder.encode(redirectUrl,"UTF8");
		//才能保证a=1&b=1不丢
		//redirectUrl = "https://manli.mynatapp.cc.cn/wechat/getCodeFromWechatAuth?redirectUrl="+redirectUrl;
		return "redirect:"+WeChatJsSDKUtil.getWechatAuthCode(redirectUrl, state, appId);
	}
	
	@ApiOperation(value="微信网页开发", notes="获取网页授权来的code")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping(value="/wechat/getCodeFromWechatAuth")
	public @ResponseBody Result getCodeFromWechatAuth(@RequestBody QueryParamsWechatAuth wechatAuth) throws Exception {
		SysWechatConfig config = weChatConfigUtil.getWeChatByAppid(appId);
		WeChat weChat = new WeChat(config.getAppId(), config.getAppSecret());
		//weChatOverUtil.getAccessToken()
		WeChatJsSdkAuthPojo authPojo = WeChatJsSDKUtil.getOpenIdInfoByCode(config.getAppId(), config.getAppSecret(), wechatAuth.getCode());
		WeChatUserManage weChatUserManage = new WeChatUserManage(config.getAppId(), config.getAppSecret());
		JSONObject json = weChatUserManage.getUserUnionId(weChatOverUtil.getAccessToken(weChat),authPojo.getOpenid());
		WeChatUserInfo weChatUserInfo = weChatUserManage.getUserUnionIdFromJSONObject(json);
		if (weChatUserInfo == null){
			throw new MyException(ResultEnums.UNKNOW_WECHAT_USER_INFO);
		}
		//用户信息写入数据库
        WeChatUserInfo retWeChatUserInfo = wechatService.saveUpdateWeChatUserInfo(weChatUserInfo.getOpenid());
		//设置token或则session
		Map<String,Object> claims = new HashMap<String, Object>();
		claims.put("openid", retWeChatUserInfo.getOpenid());
		claims.put("unionid", retWeChatUserInfo.getUnionid());
		String auth_token_wechat = JwtUtils.createJWT(claims, JwtAuthTokenTimeConfig.JwtAuthTokenWechatExpireTime);
		/**
		 * 增加refresh_token用于token过期续期
		 */
		claims.put("randomNum", RandomUtils.getRandNumByLength(10));
		String refresh_token_wechat = JwtUtils.createJWT(claims, JwtAuthTokenTimeConfig.JwtRefreshTokenWechatExpireTime);
		//返回token或则session
		//sessionInfo存入redis
		SessionInfo sessionInfo = new SessionInfo();
		sessionInfo.setWeChatUserInfo(retWeChatUserInfo);
		redisTemplate.opsForValue().set("auth_token_wechat:"+sessionInfo.getWeChatUserInfo().getOpenid(), sessionInfo,JwtAuthTokenTimeConfig.JwtAuthTokenRedisWechatExpireTime, TimeUnit.SECONDS);
		JSONObject object = new JSONObject();
		object.put("auth_token", auth_token_wechat);
		object.put("refresh_token", refresh_token_wechat);
		object.put("sessionInfo",sessionInfo);
		return ResultUtil.success(object);
	}

	@SuppressWarnings("unchecked")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@PostMapping(value="/wechat/wechatForRefreshToken")
	public @ResponseBody Result wechatForRefreshToken(HttpServletRequest request, HttpServletResponse response, @RequestBody QueryParamsRefreshToken refreshToken)throws Exception {
		/**
		 * 判断refresh是否有效
		 * 如果有效怎刷新auth_token ，如果无效就报错 提示refresh_token过期 去登陆
		 */
		Claims claims = JwtUtils.verifyJwt(refreshToken.getRefreshToken());
		if (claims!=null) {
			//有效 怎生产一个新的auto_token refresh_token redis延期
			String openid = claims.get("openid").toString();
			SessionInfo sessionInfo = (SessionInfo) redisTemplate.opsForValue().get("auth_token_wechat:"+openid);

			Map<String,Object> newclaims = new HashMap<String, Object>();
			newclaims.put("openid", sessionInfo.getWeChatUserInfo().getOpenid());
			newclaims.put("unionid", sessionInfo.getWeChatUserInfo().getUnionid());
			String auth_token_wechat = JwtUtils.createJWT(newclaims, JwtAuthTokenTimeConfig.JwtAuthTokenWechatExpireTime);
			newclaims.put("randomNum", RandomUtils.getRandNumByLength(10));
			String refresh_token_wechat = JwtUtils.createJWT(newclaims, JwtAuthTokenTimeConfig.JwtRefreshTokenWechatExpireTime);
			//sessionInfo存入redis
			redisTemplate.opsForValue().set("auth_token_wechat:"+sessionInfo.getWeChatUserInfo().getOpenid(), sessionInfo,JwtAuthTokenTimeConfig.JwtAuthTokenRedisWechatExpireTime,TimeUnit.SECONDS);
			JSONObject object = new JSONObject();
			object.put("auth_token_wechat", auth_token_wechat);
			object.put("refresh_token_wechat", refresh_token_wechat);
			object.put("sessionInfo",sessionInfo);
			return ResultUtil.success(object);
		}else {
			throw new MyException(ResultEnums.NO_LOGIN_REFRESH_TOKEN_IS_EXPIRE);
		}
	}

	
	@ApiOperation(value="微信网页开发", notes="config注入")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping(value="/wechat/getConfig")
	public @ResponseBody Result getConfig(@RequestBody QueryParamsWechatConfig wechatConfig) throws Exception {
		SysWechatConfig config = weChatConfigUtil.getWeChatByAppid(appId);
		WeChat weChat = new WeChat(config.getAppId(), config.getAppSecret());
		String jsApiTicket = weChatOverUtil.getJsapiTicket(weChat);
		String noncestr = RandomUtils.getRandNumByLength(5);
		String timestamp = System.currentTimeMillis()+"";
		String sign = WeChatSignUtils.getsig(noncestr, jsApiTicket, timestamp, wechatConfig.getUrl());
		
		JSONObject object = new JSONObject();
		object.put("noncestr", noncestr);
		object.put("timestamp", timestamp);
		object.put("sign", sign);
		object.put("appid", config.getAppId());
		
		return ResultUtil.success(object);
	}
	
	
	/*@ApiOperation(value="微信网页开发", notes="JSSDK发起一个微信支付")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping(value="/wechat/getWxpayForJsApi", method=RequestMethod.GET)
	public @ResponseBody JSONObject getWxpayForJsApi() throws Exception {
		//统一下单
		String mchID = "1583579551";
		String key = "manli111111111111111111111111111";
		String certPath = "D:\\\\Users\\\\Administrator\\\\Downloads\\\\WXCertUtil\\\\cert\\\\1583579551_20200409_cert\\\\apiclient_cert.p12";

		MyWxPayConfig wxpayconfig = new MyWxPayConfig(certPath, appId, mchID, key);
        WXPay wxpay = new WXPay(wxpayconfig);
        Map<String, String> data = new HashMap<String, String>();
        data.put("body", "漫狸充值中心");
        data.put("out_trade_no", "manli20201233348919"+RandomUtils.getRandNumByLength(5));
        data.put("device_info", "");
        data.put("fee_type", "CNY");
        data.put("total_fee", "1");
        data.put("spbill_create_ip", "123.12.12.123");
        data.put("notify_url", "http://www.manlitech.cn/wechatpay/orderPayNotify");
        data.put("trade_type", "JSAPI");  // NATIVE 此处指定为扫码支付
        data.put("openid", "oXzMAwMhnYDAcX_m9ZDAxSCjsS4c");//shensg 当时jssdk必传
        data.put("product_id", "12");
        Map<String, String> resp = null;
        try {
            resp = wxpay.unifiedOrder(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
		
		//签名
		SysWechatConfig config = weChatConfigUtil.getWeChatByAppid("wx3745551a988274db");
		String noncestr = RandomUtils.getRandNumByLength(5);
		String timestamp = System.currentTimeMillis()/1000+"";
		String packageStr = "prepay_id="+resp.get("prepay_id");
		String signType = "MD5";
		String sign = WeChatSignUtils.getsigForWxPayMD5(config.getAppId(), timestamp, noncestr, packageStr, signType ,key);
		
		//返回下单数据
		JSONObject object = new JSONObject();
		object.put("noncestr", noncestr);
		object.put("timestamp", timestamp);
		object.put("sign", sign);
		object.put("appid", config.getAppId());
		object.put("signType", signType);
		object.put("packageStr", packageStr);
		
		return object;
	}**/

	//统一下单
	/*@ApiOperation(value="微信网页开发", notes="JSSDK发起一个微信支付")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping(value="/wechat/makeWxpayOrder")
	public @ResponseBody JSONObject makeWxpayOrder(String appid,String code) throws Exception {
		SysWechatConfig config = weChatConfigUtil.getWeChatByAppid(appid);
//		WeChat weChat = new WeChat(config.getAppId(), config.getAppSecret());
		//WeChatJsSdkAuthPojo authPojo = WeChatJsSDKUtil.getOpenIdInfoByCode(config.getAppId(), config.getAppSecret(), code);
		String certPath = "D:\\\\Users\\\\Administrator\\\\Downloads\\\\WXCertUtil\\\\cert\\\\1583579551_20200409_cert\\\\apiclient_cert.p12";

		String mchID = "1601420795";
		String key = "manli111111111111111111111111111";

		MyWxPayConfig wxpayconfig = new MyWxPayConfig(certPath, "wx6f56d14c68184b2f", mchID, key);
		WXPay wxpay = new WXPay(wxpayconfig);
		Map<String, String> data = new HashMap<String, String>();
		data.put("appid","wx6f56d14c68184b2f");
		data.put("mch_id","1601420795");
		data.put("sub_appid","wx3745551a988274db");
		data.put("sub_mch_id","1601704787");
		data.put("body", "漫狸充值中心");
		data.put("out_trade_no", "manli20201233348919"+RandomUtils.getRandNumByLength(5));
		data.put("device_info", "");
		data.put("fee_type", "CNY");
		data.put("total_fee", "500");
		data.put("spbill_create_ip", "123.12.12.123");
		data.put("notify_url", "http://www.manlitech.cn/wechatpay/orderPayNotify");
		data.put("trade_type", "JSAPI");  // NATIVE 此处指定为扫码支付
		data.put("openid", "oJRQnwvbiRCQGmw6xzMsBCme2ILg");//shensg 当时jssdk必传
		data.put("product_id", "12");
		data.put("goods_tag","20200914");
		Map<String, String> resp = null;
		try {
			resp = wxpay.unifiedOrder(data);
		} catch (Exception e) {
			e.printStackTrace();
		}

		//签名
//		SysWechatConfig config = weChatConfigUtil.getWeChatByAppid(appid);
		String noncestr = RandomUtils.getRandNumByLength(5);
		String timestamp = System.currentTimeMillis()/1000+"";
		String packageStr = "prepay_id="+resp.get("prepay_id");
		String signType = "MD5";
		String sign = WeChatSignUtils.getsigForWxPayMD5("wx6f56d14c68184b2f", timestamp, noncestr, packageStr, signType ,key);

		//返回下单数据
		JSONObject object = new JSONObject();
		object.put("noncestr", noncestr);
		object.put("timestamp", timestamp);
		object.put("sign", sign);
		object.put("appid", appid);
		object.put("signType", signType);
		object.put("packageStr", packageStr);
		System.out.println(object);
		return object;
	}*/

	//拉取适用卡券列表并获取用户选择信息
	/*@ApiOperation(value="微信网页开发", notes="JSSDK拉取适用卡券列表并获取用户选择信息")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping(value="/wechat/getUserCardList", method=RequestMethod.POST)
	public @ResponseBody TreeMap<String,String> getUserCardList(String appid) throws Exception {
		SysWechatConfig config = weChatConfigUtil.getWeChatByAppid(appid);
		//获取用户卡券code
		WeChat weChat = new WeChat(appid,config.getAppSecret());
		WeChatCardTicket weChatCardTicket = new WeChatCardTicket(appid,config.getAppSecret());
		WeChatUserCardList weChatUserCardList = new WeChatUserCardList();
		weChatUserCardList.setOpenid("oXzMAwEH0NBvwWlcSSN-z3-Uz624");
		weChatUserCardList.setCard_id("pXzMAwIIDiUzjFesgB_7dkK6d5vM");
		JSONObject jsonObject = weChatCardTicket.queryUserCardList(weChatOverUtil.getAccessToken(weChat),weChatUserCardList);
		JSONObject card = (JSONObject)jsonObject.getJSONArray("card_list").get(0);

		//签名
		String noncestr = RandomUtils.getRandNumByLength(5);
		String timestamp = System.currentTimeMillis()/1000+"";
		String signType = "SHA1";

		//返回下单数据
		TreeMap<String,String> object = new TreeMap();
		object.put("shopId", "");
		object.put("cardType", "GROUPON");
		object.put("cardType", "");
		object.put("cardId", "pXzMAwIIDiUzjFesgB_7dkK6d5vM");
		object.put("nonceStr", noncestr);
		object.put("timestamp", timestamp);
		object.put("signType", signType);
		object.put("cardSign", WeChatSignUtils.getSha1(object));
		object.put("cardCode", card.getString("code"));

		System.out.println(object);
		return object;
	}*/


	//保存用户定位
	@ApiOperation(value="微信网页开发", notes="保存用户定位及天气")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping(value="/wechat/saveUserLocation", method=RequestMethod.POST)
	public @ResponseBody Result saveUserLocation(@RequestBody WeChatUserLocation location) throws Exception {
		location.setCreateTime(new Date());
		weChatUserLocationService.save(location);
		JSONObject briefcondition = WeatherUtil.briefcondition(location.getLongitude(),location.getLatitude());
		JSONObject briefforecast6days = WeatherUtil.briefforecast6days(location.getLongitude(),location.getLatitude());
		JSONObject locationName = TencentMapUtils.getLocationByLatLng(location.getLatitude(),location.getLongitude(),"0");
		JSONObject data = new JSONObject();
		data.put("briefcondition",briefcondition);
		data.put("briefforecast6days",briefforecast6days);
		data.put("locationName",locationName);
		return ResultUtil.success(data);
	}

	@ApiOperation(value="微信公众号", notes="获取带参数二维码")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping("/wechat/getQrCode")
	public @ResponseBody Result getQrCode(WeChatQrcodePojo weChatQrcodePojo, HttpServletResponse response) throws Exception {
		SysWechatConfig config = weChatConfigUtil.getWeChatByAppid(appId);
		WeChat weChat = new WeChat(config.getAppId(), config.getAppSecret());
		String accessToken = weChatOverUtil.getAccessToken(weChat);
		String param = WeChatQrcodeUtil.getParam(weChatQrcodePojo);
		return ResultUtil.success(WeChatQrcodeUtil.create(accessToken,param));
	}

}
